package core.helpers;

import org.openqa.selenium.By;
import org.testng.Assert;

import core.Pilot;

/**
 * Class provides functions for values testing
 */
public class TestHelper
{
	protected static Pilot manager;

	/**
	 * Initializes TestHelper
	 * @param p_manager
	 *            ApplicationManager instance
	 */
	public TestHelper(Pilot p_manager)
	{
		manager = p_manager;
	}

	/**
	 * Tests for equivalence
	 * @param p_actual
	 *            Actual value
	 * @param p_expected
	 *            Expected value
	 */
	public void forEquivalence(boolean p_actual, boolean p_expected)
	{
		try
		{
			Assert.assertEquals(p_actual, p_expected);
			manager.dashboard().setStatus(1);
		}
		catch (AssertionError p_ex)
		{
			throwError();
		}
	}

	/**
	 * Tests for equivalence
	 * @param p_actual
	 *            Actual value
	 * @param p_expected
	 *            Expected value
	 * @param p_errorMessage
	 *            Error message
	 */
	public void forEquivalence(boolean p_actual, boolean p_expected, String p_errorMessage)
	{
		try
		{
			Assert.assertEquals(p_actual, p_expected);
			manager.dashboard().setStatus(1);
		}
		catch (AssertionError p_ex)
		{
			throwError(p_errorMessage);
		}
	}

	/**
	 * Tests for true
	 * @param p_actual
	 *            Actual value
	 * @param p_expected
	 *            Expected value
	 * @param p_warningMessage
	 *            Warning message text
	 */
	public void forTrue(boolean p_actual)
	{
		try
		{
			Assert.assertTrue(p_actual);
			manager.dashboard().setStatus(1);
		}
		catch (AssertionError p_ex)
		{
			throwError();
		}
	}

	/**
	 * Tests for true
	 * @param p_actual
	 *            Actual value
	 * @param p_errorMessage
	 *            Error message
	 */
	public void forTrue(boolean p_actual, String p_errorMessage)
	{
		try
		{
			Assert.assertTrue(p_actual);
			manager.dashboard().setStatus(1);
		}
		catch (AssertionError p_ex)
		{
			throwError(p_errorMessage);
		}
	}

	/**
	 * Tests for false
	 * @param p_actual
	 *            Actual value
	 * @param p_errorMessage
	 *            Error message
	 */
	public void forFalse(boolean p_actual, String p_errorMessage)
	{
		try
		{
			Assert.assertFalse(p_actual);
		}
		catch (AssertionError p_ex)
		{
			throwError(p_errorMessage);
		}
	}

	/**
	 * Tests for false
	 * @param p_actual
	 *            Actual value
	 */
	public void forFalse(boolean p_actual)
	{
		try
		{
			Assert.assertFalse(p_actual);
			manager.dashboard().setStatus(1);
		}
		catch (AssertionError p_ex)
		{
			throwError();
		}
	}

	/**
	 * Tests for false
	 * @param p_actual
	 *            Actual value
	 */
	public void forErrors()
	{
		if (!manager.log().isErrors())
		{
			manager.dashboard().setStatus(1);
		}
		else
		{
			manager.dashboard().setStatus(0);
			throwError();
		}
	}

	/**
	 * Throws assertion error
	 * @param p_errors
	 *            Error messages list
	 * @throws AssertionError
	 */
	protected void throwError(String... p_errors) throws AssertionError
	{
		if (p_errors.length > 0)
		{
			for (int i = 0; i < p_errors.length; i++)
			{
				manager.log().writeError(p_errors[i]);
			}
		}

		if (manager.dashboard().getStatus() != 0)
		{
			manager.dashboard().setStatus(0);
		}
		throw new AssertionError(manager.log().getErrorsAndWarnings());
	}

	/**
	 * Compares numbers to verify that actual value greater than expected
	 * @param p_actual
	 * @param p_expected
	 * @param p_message
	 */
	public void forGreaterOrEqual(String p_actual, String p_expected, String p_message)
	{
		try
		{
			Integer actual = Integer.valueOf(p_actual);
			Integer expected = Integer.valueOf(p_expected);
			Assert.assertTrue(actual >= expected);
		}
		catch (AssertionError p_ex)
		{
			manager.log().error(p_message + " : Actual [" + p_actual + "] is lower than expected [" + p_expected + "] ");
		}
	}

	/**
	 * Compares numbers to verify that actual value greater than expected
	 * @param p_actual
	 * @param p_expected
	 * @param p_message
	 */
	public void forGreaterOrEqual(Integer p_actual, Integer p_expected, String p_message)
	{
		try
		{
			Assert.assertTrue(p_actual >= p_expected);
		}
		catch (AssertionError p_ex)
		{
			manager.log().error(p_message + " : Actual [" + p_actual + "] is lower than expected [" + p_expected + "] ");
		}
	}

	/**
	 * Compares numbers to verify that actual value lover than expected
	 * @param p_actual
	 * @param p_expected
	 * @param p_message
	 */
	public void forLowerOrEqual(String p_actual, String p_expected, String p_message)
	{
		try
		{
			Integer actual = Integer.valueOf(p_actual);
			Integer expected = Integer.valueOf(p_expected);
			Assert.assertTrue(actual <= expected);
		}
		catch (AssertionError E)
		{
			manager.log().error(p_message + " : Actual [" + p_actual + "] is greater than expected [" + p_expected + "]");
		}
	}

	/**
	 * Compares numbers to verify that actual value lover than expected
	 * @param p_actual
	 * @param p_expected
	 * @param p_message
	 */
	public void forLoverOrEqual(Integer p_actual, Integer p_expected, String p_message)
	{
		try
		{
			Assert.assertTrue(p_actual <= p_expected);
		}
		catch (AssertionError p_ex)
		{
			manager.log().error(p_message + " : Actual [" + p_actual + "] is greater than expected [" + p_expected + "] ");
		}
	}

	/**
	 * Gets current method name
	 * @return Method name
	 */
	private String getMethodName()
	{
		StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
		StackTraceElement stackTraceElement = stacktrace[4];
		String methodName = stackTraceElement.getMethodName();
		return methodName;
	}

	public void assertEquals(String p_actual, String p_expected, String p_message)
	{
		try
		{
			Assert.assertEquals(p_actual, p_expected);
		}
		catch (AssertionError p_ex)
		{
			manager.log().error(p_message + " : Actual [" + p_actual + "] is not equal to [" + p_expected + "] ");
		}
	}

	public void assertGreater(Integer p_expected, Integer p_actual, String p_message)
	{
		try
		{
			Assert.assertTrue(p_actual > p_expected);

		}
		catch (AssertionError p_ex)
		{
			manager.log().error(p_message + " : Actual [" + p_actual + "] is not greater than [" + p_expected + "] ");
		}
	}

	public void assertLower(Integer p_expected, Integer p_actual, String p_message)
	{
		try
		{
			Assert.assertTrue(p_actual < p_expected);

		}
		catch (AssertionError p_ex)
		{
			manager.log().error(p_message + " : Actual [" + p_actual + "] is not lower than [" + p_expected + "] ");
		}
	}

	/**
	 * Checks for: web element is visible on a page
	 * @param p_actual
	 * @param p_errorMessage
	 */
	public void checkForVisibility(By p_locator, String p_errorMessage)
	{
		boolean isVisible = true;

		if (!manager.driver().waitForVisible(p_locator))
		{
			isVisible = false;
			p_errorMessage += "\n[ACTUAL] web element not found: " + p_locator
					+ " [EXPECTED] web element is found";
		}

		Assert.assertTrue(isVisible, p_errorMessage);
	}

	/**
	 * Checks for: one from two web elements is visible on a page
	 * @param p_locator1
	 * @param p_locator2
	 * @param p_errorMessage
	 */
	public void checkForVisibilityOr(By p_locator1, By p_locator2, String p_errorMessage)
	{
		boolean isVisible = true;

		if (!manager.driver().waitForVisible(p_locator1) || !manager.driver().waitForVisible(p_locator2))
		{
			isVisible = false;
			p_errorMessage += "\n[ACTUAL] web elements not found: " + p_locator1 + " AND " + p_locator2
					+ " [EXPECTED] one from two web elements is found";
		}

		Assert.assertTrue(isVisible, p_errorMessage);
	}

	/**
	 * Checks for: web element is invisible on a page
	 * @param p_locator
	 * @param p_errorMessage
	 */
	public void checkForInvisibility(By p_locator, String p_errorMessage)
	{
		boolean isVisible = false;

		if (!manager.driver().waitForInvisible(p_locator))
		{
			isVisible = true;
			p_errorMessage += "\n[ACTUAL] web element is found: " + p_locator
					+ " [EXPECTED] web element not found";
		}

		Assert.assertFalse(isVisible, p_errorMessage);
	}

	/**
	 * Checks for: actual string does not equal to expected string
	 * @param p_actual
	 * @param p_expected
	 * @param p_errorMessage
	 */
	public void checkForNotEquals(String p_actual, String p_expected, String p_errorMessage)
	{
		boolean isEquals = false;

		if (p_actual.equals(p_expected))
		{
			isEquals = true;
			p_errorMessage += "\n[ACTUAL] '" + p_actual + "' = '" + p_expected
					+ "' [EXPECTED] strings are not equals";
		}

		Assert.assertFalse(isEquals, p_errorMessage);
	}

	/**
	 * Checks for: actual string is equal to expected string
	 * @param p_actual
	 * @param p_expected
	 * @param p_errorMessage
	 */
	public void checkForEquals(String p_actual, String p_expected, String p_errorMessage)
	{
		boolean isEquals = true;

		if (!p_actual.equals(p_expected))
		{
			isEquals = false;
			p_errorMessage += "\n[ACTUAL] '" + p_actual + "' != '" + p_expected
					+ "' [EXPECTED] strings are equals";
		}

		Assert.assertTrue(isEquals, p_errorMessage);
	}

	/**
	 * Checks for: actual numver is equals to expected number
	 * @param p_actual
	 * @param p_expected
	 * @param p_errorMessage
	 */
	public void checkForEquals(int p_actual, int p_expected, String p_errorMessage)
	{
		boolean isEquals = true;

		if (p_actual != p_expected)
		{
			isEquals = false;
			p_errorMessage += "\n[ACTUAL] '" + p_actual + "' != '" + p_expected
					+ "' [EXPECTED] numbers are equals";
		}

		Assert.assertTrue(isEquals, p_errorMessage);
	}

	/**
	 * Checks for: actual number is not equal to expected number
	 * @param p_actual
	 * @param p_expected
	 * @param p_errorMessage
	 */
	public void checkForNotEqual(int p_actual, int p_expected, String p_errorMessage)
	{
		boolean isEquals = false;

		if (p_actual == p_expected)
		{
			isEquals = true;
			p_errorMessage += "\n[ACTUAL] '" + p_actual + "' = '" + p_expected
					+ "' [EXPECTED]: numbers are not equals";
		}

		Assert.assertFalse(isEquals, p_errorMessage);
	}

	/**
	 * Checks for: actual string contains expected string
	 * @param p_actual
	 * @param p_expected
	 * @param p_errorMessage
	 */
	public void checkForContains(String p_actual, String p_expected, String p_errorMessage)
	{
		boolean isContains = true;

		if (!p_actual.contains(p_expected))
		{
			isContains = false;
			p_errorMessage += "\n[ACTUAL] '" + p_actual + "' does not contain '" + p_expected
					+ "' [EXPECTED] '" + p_actual + "' contains '" + p_expected + "'";
		}

		Assert.assertTrue(isContains, p_errorMessage);
	}

	/**
	 * Checks for: actual string does not contain expected string
	 * @param p_actual
	 * @param p_expected
	 * @param p_errorMessage
	 */
	public void checkForNotContains(String p_actual, String p_expected, String p_errorMessage)
	{
		boolean isContains = false;

		if (p_actual.contains(p_expected))
		{
			isContains = true;
			p_errorMessage += "\n[ACTUAL] '" + p_actual + "' contains '" + p_expected
					+ "' [EXPECTED] actual string does not contain expected string";
		}

		Assert.assertFalse(isContains, p_errorMessage);
	}

	/**
	 * Checks for: actual number is greater than expected number, or is equals to expected number
	 * @param p_actual
	 * @param p_expected
	 * @param p_errorMessage
	 */
	public void checkForGreaterOrEqual(int p_actual, int p_expected, String p_errorMessage)
	{
		boolean isGreaterOrEqual = true;

		if (p_actual < p_expected)
		{
			isGreaterOrEqual = false;
			p_errorMessage += "\n[ACTUAL] " + p_actual + " < " + p_expected
					+ " [EXPECTED] actual number >= expected number";
		}

		Assert.assertTrue(isGreaterOrEqual, p_errorMessage);
	}

	/**
	 * Checks for: actual number is less than expected number, or is equals to expected number
	 * @param p_actual
	 * @param p_expected
	 * @param p_errorMessage
	 */
	public void checkForLessOrEqual(int p_actual, int p_expected, String p_errorMessage)
	{
		boolean isLessOrEqual = true;

		if (p_actual > p_expected)
		{
			isLessOrEqual = false;
			p_errorMessage += "\n[ACTUAL] " + p_actual + " > " + p_expected
					+ " [EXPECTED] actual number <= expected number";
		}

		Assert.assertTrue(isLessOrEqual, p_errorMessage);
	}

	/**
	 * Checks for: actual number is less than expected number
	 * @param p_actual
	 * @param p_expected
	 * @param p_errorMessage
	 */
	public void checkForLess(int p_actual, int p_expected, String p_errorMessage)
	{
		boolean isLess = true;

		if (p_actual >= p_expected)
		{
			isLess = false;
			p_errorMessage += "\n[ACTUAL] " + p_actual + " >= " + p_expected
					+ " [EXPECTED] actual number < expected number";
		}

		Assert.assertTrue(isLess, p_errorMessage);
	}

	/**
	 * Checks for: actual number is greater than expected number
	 * @param p_actual
	 * @param p_expected
	 * @param p_errorMessage
	 */
	public void checkForGreater(int p_actual, int p_expected, String p_errorMessage)
	{
		boolean isGreater = true;

		if (p_actual <= p_expected)
		{
			isGreater = false;
			p_errorMessage += "\n[ACTUAL] " + p_actual + " <= " + p_expected
					+ " [EXPECTED] actual number > expected number";
		}

		Assert.assertTrue(isGreater, p_errorMessage);
	}

	/**
	 * Checks for: string array contains expected string
	 * @param p_actuals
	 * @param p_expected
	 * @param p_errorMessage
	 */
	public void checkForContains(String[] p_actuals, String p_expected, String p_errorMessage)
	{
		Boolean[] errors = new Boolean[p_actuals.length];
		int i = 0;

		for (String actual : p_actuals)
		{
			if (!actual.contains(p_expected))
			{
				manager.log().warn("Check for containing: [" + actual + ":" + p_expected + "] => " + false);
				p_errorMessage += "\n[ACTUAL] '" + actual + "' does not contain '" + p_expected
						+ "' [EXPECTED] actual string contains expected string";
				errors[i] = true;
			}
			else
			{
				manager.log().info("Check for containing: [" + actual + ":" + p_expected + "] => " + true);
				errors[i] = false;
			}

			i++;
		}

		for (boolean error : errors)
		{
			Assert.assertFalse(error, p_errorMessage);
		}
	}

	public void checkForEquivalence(String p_actual, String p_expected, String p_errorMessage)
	{
		Assert.assertTrue(p_actual.equals(p_expected), p_errorMessage);
	}

	/**
	 * Checks four strings for equivalence (or)
	 * @param p_actual1
	 * @param p_expected1
	 * @param p_actual2
	 * @param p_expected2
	 * @param p_errorMessage
	 */
	public void checkForEquivalence(String p_actual1, String p_expected1, String p_actual2, String p_expected2, String p_errorMessage)
	{
		Assert.assertTrue(p_actual1.equals(p_expected1) || p_actual2.equals(p_expected2), p_errorMessage);
	}

}
